﻿using Ghostscript.NET;
using Ghostscript.NET.Rasterizer;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Management;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace Dx.Common
{
    /// <summary>
    /// 公共方法
    /// </summary>
    public abstract class FuncBaseHelper : DesHelper
    {
        /// <summary>
        /// 数据写入配置文件INI
        /// </summary>
        /// <param name="section">写入的节点</param>
        /// <param name="key">写入的键</param>
        /// <param name="val">写入值</param>
        /// <returns></returns>
        public static bool SetIniValue(string section, string key, string val)
        {
            long i = WritePrivateProfileString(section, key, val, ParametersBaseHelper.UserSettingIniPath);
            if (i > 0)
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// 获取INI文件
        /// </summary>
        /// <param name="section">写入的节点</param>
        /// <param name="key">写入的键</param>
        /// <returns>为空表示失败或者没有数据</returns>
        public static string GetIniValue(string section, string key)
        {
            StringBuilder strB = new StringBuilder(500);
            //第三个参数表示没有值是返回的数据，此处没有值返回空“”
            GetPrivateProfileString(section, key, "", strB, 500, ParametersBaseHelper.UserSettingIniPath);
            return strB.ToString();
        }

        /// <summary>
        /// 根据文件地址删除文件
        /// </summary>
        /// <param name="filePath"></param>
        public static void DeleteFile(string filePath)
        {
            try
            {
                if (File.Exists(filePath))
                {
                    File.Delete(filePath);
                }
            }
            catch { }
        }

        /// <summary>
        /// 删除目录下所有文件
        /// </summary>
        /// <param name="directoryInfo"></param>
        public static void DeleteAllFile(DirectoryInfo directoryInfo)
        {
            try
            {
                //directoryInfo.Delete(true);不能这样直接删除文件夹，wps占用
                foreach (FileInfo item in directoryInfo.GetFiles())
                {
                    try
                    {
                        item.Delete();
                    }
                    catch { }
                }
                foreach (DirectoryInfo item in directoryInfo.GetDirectories())
                {
                    DeleteAllFile(item);
                }
            }
            catch { }
        }

        /// <summary>
        /// 根据文件的扩展名，判断是否需要存储的文件
        /// </summary>
        /// <param name="fileName">带扩展名的文件名</param>
        /// <param name="contentType">mime类型，有的文件没扩展名，但mime类型符合缓存逻辑</param>
        /// <param name="uri">URL地址，用于判断是否包含“v=”的参数，以便于进一步判断是否进行缓存</param>
        /// <returns></returns>
        public static bool NeedSaveByExt(string fileName, string contentType, Uri uri)
        {

            string ext = Path.GetExtension(fileName).ToLower();
            switch (ext)
            {
                case ".js":
                case ".css":
                case ".jpg":
                case ".jpeg":
                case ".bmp":
                case ".png":
                case ".gif":
                case ".ico":
                case ".svg":
                case ".ttf":
                case ".woff":
                case ".woff2":
                case ".eot":
                case ".mp3":
                case ".mp4":
                    return true;
                default:
                    //判断返回的媒体类型，有的时候返回的没扩展名，但是需要缓存的对象，比如c#动态打包的css文件，形如：https://officeweb365.com/Content/css?v=gV4hLx2wMNPtRlvNaYaW5R_tzyrnJr15qo4QyApcF4E1
                    //其类型为：content-type:text/css; charset=utf-8
                    //有一些业务图片，比如：https://bb.daxiit.net/compilation/file/img?fid=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJyZXNvdXJjZSI6
                    //它本身的Content-Type为image/jpg，但是是业务里的图片，业务里的图片可能很多，我们就不缓存了。交给浏览器自己处理吧
                    //这里总体约定：1、扩展名未知，2、mime类型需要缓存但是不包含v=标识，则认为不需要缓存
                    if (string.IsNullOrEmpty(contentType))
                    {
                        return false;
                    }
                    bool uriHasV = UriHasV(uri.Query);
                    if (!uriHasV)
                    {
                        return false;//不包含v=的参数，则不缓存了
                    }
                    string mime = contentType.Split(';')[0];
                    switch (mime)
                    {
                        case "text/css":
                        case "application/x-javascript":
                        case "audio/mp3":
                        case "video/mpeg4":
                            return true;
                        default:
                            if (mime.StartsWith("image") || mime.StartsWith("application/font"))
                            {
                                return true;
                            }
                            return false;
                    }
            }
        }

        /// <summary>
        /// 判断URL地址中是否包含“v=”的参数，以便于进一步判断是否进行缓存
        /// </summary>
        /// <param name="queryStr">url的查询字符串</param>
        /// <returns></returns>
        public static bool UriHasV(string queryStr)
        {
            if (string.IsNullOrEmpty(queryStr))
            {
                return false;
            }
            string[] queryArr = queryStr.Split('&');
            return queryArr.Any(val => val.StartsWith("v="));
        }

        /// <summary>
        /// 从URI中获取请求的文件名，如果文件名太长，则返回空字符串。
        /// </summary>
        /// <param name="url">URL请求地址</param>
        /// <param name="hasVersion">是否包含版本号，若包含，则文件名后面增加 .v0</param>
        /// <returns></returns>
        public static string GetFileName(string url, bool hasVersion = true)
        {
            try
            {
                Uri uri = new Uri(url, UriKind.Absolute);
                return GetFileName(uri, hasVersion);
            }
            catch
            {
                return string.Empty;
            }
        }

        /// <summary>
        /// 从URI中获取请求的文件名，如果文件名太长，则返回空字符串。
        /// </summary>
        /// <param name="uri">URL请求地址</param>
        /// <param name="hasVersion">是否包含版本号，若包含，则文件名后面增加 .v0</param>
        /// <returns></returns>
        public static string GetFileName(Uri uri, bool hasVersion = true)
        {
            //获取文件名
            string fileName = Path.GetFileName(uri.AbsolutePath);
            //有的文件名太长。比如一些svg请求。指定的路径或文件名太长，或者两者都太长。完全限定文件名必须少于 260 个字符，并且目录名必须少于 248 个字符。
            if (string.IsNullOrEmpty(fileName) || fileName.Length > 128)
            {
                return string.Empty;
            }
            if (!hasVersion)
            {
                return fileName;
            }
            string queryStr = uri.Query.ToLower();
            if (queryStr.Contains("v="))
            {
                int pos0 = queryStr.IndexOf("v=");
                int pos1 = queryStr.IndexOf("&", pos0 + 1);
                string ver = string.Empty;
                if (pos1 > -1)
                {
                    ver = queryStr.Substring(pos0 + 2, pos1 - pos0 - 2);
                }
                else
                {
                    ver = queryStr.Substring(pos0 + 2);
                }
                return fileName + ".v" + ver;
            }
            else
            {
                return fileName + ".v0";
            }
        }

        /// <summary>
        /// 获取http响应头content-type类型
        /// </summary>
        /// <param name="fileExt">文件扩展名</param>
        /// <returns></returns>
        public static string GetContentType(string fileExt)
        {
            string ext = string.Empty;
            if (fileExt.StartsWith("."))
            {
                ext = fileExt.Substring(1);
            }
            else
            {
                ext = fileExt;
            }
            switch (ext.ToLower())
            {
                case "js":
                    return "content-type: application/x-javascript";
                case "css":
                    return "content-type: text/css";
                case "jpg":
                case "jpeg":
                case "bmp":
                case "png":
                case "gif":
                    return "content-type: image/" + ext;
                case "ico":
                    return "image/x-icon";
                case "svg":
                    return "content-type: text/xml";
                case "ttf":
                case "woff":
                case "woff2":
                case "eot":
                    return "content-type: application/font-" + ext;
                case "mp3":
                    return "content-type: audio/mp3";
                case "mp4":
                    return "content-type: video/mpeg4";
                default:
                    return string.Empty;
            }
        }

        /// <summary>
        /// 注册Aspose相关第三方插件
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static bool OnLoadAspDLL(string type)
        {
            bool isRegister = true;
            try
            {
                var register = ParametersBaseHelper.Register;
                byte[] array = Encoding.ASCII.GetBytes(register);
                using (MemoryStream stream = new MemoryStream(array))
                {
                    switch (type)
                    {
                        case ".doc":
                        case ".wps":
                        case ".docx":
                        case "word":
                            {
                                var license = new Aspose.Words.License();
                                license.SetLicense(stream);
                            }
                            break;
                        case ".pdf":
                        case "pdf":
                            {
                                var license = new Aspose.Pdf.License();
                                license.SetLicense(stream);
                            }
                            break;
                        case ".ppt":
                        case "ppt":
                            {
                                var license = new Aspose.Slides.License();
                                license.SetLicense(stream);
                            }
                            break;
                        case "xlsx":
                        case "csv":
                            {
                                var license = new Aspose.Cells.License();
                                license.SetLicense(stream);
                            }
                            break;
                        default:
                            break;
                    }
                }
            }
            catch (Exception ex) { LogHelper.Instance.Error(ex); isRegister = false; }
            return isRegister;
        }

        public static byte[] GetBt(string origf, string name)
        {
            string base64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(origf));
            string path = AppDomain.CurrentDomain.BaseDirectory + name;
            using (FileStream stm = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))//Properties.Resources.
            {
                using (BinaryReader btRead = new BinaryReader(stm))
                {
                    stm.Seek(7, SeekOrigin.Begin);
                    byte count = btRead.ReadByte();
                    for (int i = 0; i < count; i++)
                    {
                        byte nameLen = btRead.ReadByte();
                        byte[] btName = btRead.ReadBytes(nameLen);
                        string nameBase64 = Encoding.UTF8.GetString(btName.Select(m => (byte)(m / 2)).ToArray());
                        long offset = btRead.ReadInt64();
                        long length = btRead.ReadInt64();
                        if (nameBase64 == base64)
                        {
                            stm.Seek(offset, SeekOrigin.Begin);
                            byte[] btFile = btRead.ReadBytes((int)length);
                            return btFile;
                        }
                    }
                }
                stm.Close();
            }
            return null;
        }

        /// <summary>
        /// 获取PDF转换为图片后的页数
        /// </summary>
        /// <param name="pdfFile"></param>
        /// <returns></returns>
        public static int GetPdfToImgCount(string pdfFile)
        {
            //执行pdf转图片必须要的dll文件
            var pageCount = 0;
            string execDllFile = Path.Combine(ParametersBaseHelper.BaseDirectoryPath, (Environment.Is64BitProcess ? "gsdll64" : "gsdll32") + ".dll");
            if (!File.Exists(execDllFile))
            {
                LogHelper.Instance.Error("PDF转图片出现异常现象:未发现必要dll文件(gsdll.dll)");
            }
            else
            {
                try
                {
                    using (GhostscriptRasterizer ghostscriptRasterizer = new GhostscriptRasterizer())
                    {
                        List<string> paramStrs = new List<string>()
                        {
                            "-dSAFER",
                            "-dBATCH",
                            "-dNOPAUSE",
                            "-dPDFSETTINGS=/screen",
                            "-dTextAlphaBits=4",
                            "-dGraphicsAlphaBits=4",
                            "-dDOINTERPOLATE",
                            "-dINTERPOLATEMAX=3",
                            "-dDownScaleFactor=2"
                        };
                        ghostscriptRasterizer.CustomSwitches.AddRange(paramStrs);
                        var pdfSavePath = Path.Combine(Path.GetTempPath(), $"MarkBook\\InsertModel\\{Guid.NewGuid().ToString()}.pdf");

                        File.Copy(pdfFile, pdfSavePath, true);
                        ghostscriptRasterizer.Open(pdfSavePath, new GhostscriptVersionInfo(execDllFile), true);
                        pageCount = ghostscriptRasterizer.PageCount;
                        ghostscriptRasterizer.Close();
                        File.Delete(pdfSavePath);
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.Instance.Error("PDF转图片出现异常现象:" + ex);
                }
            }
            return pageCount;
        }

        /// <summary>
        ///获取cpu序列号
        /// </summary>
        /// <returns></returns>
        public static string GetCpu()
        {
            string cpuStr = string.Empty;
            try
            {
                using (ManagementClass management = new ManagementClass("Win32_Processor"))
                {
                    ManagementObjectCollection managements = management.GetInstances();
                    foreach (ManagementObject mo in managements)
                    {
                        cpuStr = mo.Properties["ProcessorId"].Value.ToString();
                        mo.Dispose();
                    }
                }
                return cpuStr;
            }
            catch (Exception ex) { LogHelper.Instance.Error(ex); }
            return cpuStr;
        }

        /// <summary>
        /// 获取硬盘ID序列号
        /// </summary>
        /// <returns></returns>
        public static string GetHDID()
        {
            string HDStr = string.Empty;
            try
            {
                using (ManagementClass management = new ManagementClass("Win32_DiskDrive"))
                {
                    ManagementObjectCollection managements = management.GetInstances();
                    foreach (ManagementObject mo in managements)
                    {
                        HDStr = (string)mo.Properties["Model"].Value;
                        mo.Dispose();
                    }
                }
            }
            catch (Exception ex) { LogHelper.Instance.Error(ex); }
            return HDStr;
        }

        /// <summary>
        /// 获取httpClient接口传递头部信息
        /// </summary>
        /// <returns></returns>
        public static Dictionary<string, string> GetHttpHeaderDics()
        {
            Dictionary<string, string> headerDirs = new Dictionary<string, string>();
            headerDirs.Add("Authorization", ParametersBaseHelper.Token);
            headerDirs.Add("deviceCode", ParametersBaseHelper.DeveiceCode);
            return headerDirs;
        }

        /// <summary>
        /// 批量上传文件
        /// (适配快书所有，只需要传递文件路径数组)
        /// </summary>
        /// <param name="files"></param>
        /// <returns></returns>
        public static async Task<string> UploadFiles(string[] files)
        {
            string result = string.Empty;
            try
            {
                //将文件批量给上传下
                //上传当前文档给后端，并将获取到的文件id赋值给insertPDFInfo.FileId
                var httpHelper = new HttpBaseHelper();
                string address = $"{ParametersBaseHelper.BackendURL}{ParametersBaseHelper.UploadFilesURL}";

                result = await httpHelper.UploadFilesAsync(address, GetHttpHeaderDics(), files, "files");
            }
            catch (Exception ex)
            {
                LogHelper.Instance.Error(ex);
            }
            return result;
        }

        /// <summary>
        /// 批量上传文件
        /// (适配快书所有，只需要传递文件路径数组)
        /// </summary>
        /// <param name="dic"></param>
        /// <returns></returns>
        public static async Task<string> UploadFiles(Dictionary<string, Stream> dic)
        {
            string result = string.Empty;
            try
            {
                //将文件批量给上传下
                //上传当前文档给后端，并将获取到的文件id赋值给insertPDFInfo.FileId
                var httpHelper = new HttpBaseHelper();
                string address = $"{ParametersBaseHelper.BackendURL}{ParametersBaseHelper.UploadFilesURLV1}";

                result = await httpHelper.UploadFilesAsync(address, GetHttpHeaderDics(), dic, "files");
            }
            catch (Exception ex)
            {
                LogHelper.Instance.Error(ex);
            }
            return result;
        }

        /// <summary>
        /// 根据文件流获取文件类型
        /// </summary>
        /// <param name="fs"></param>
        /// <returns></returns>
        public static string GetFileType(Stream fs)
        {
            foreach (var signature in ParametersBaseHelper.FileSignatures)
            {
                byte[] buffer = new byte[signature.Value.Length];
                fs.Seek(0, SeekOrigin.Begin);
                fs.Read(buffer, 0, buffer.Length);

                if (MatchesSignature(buffer, signature.Value))
                {
                    if (signature.Key == "ZIP")
                    {
                        // Further check for DOCX, XLSX, PPTX
                        return GetOfficeFileType(fs);
                    }
                    return signature.Key;
                }
            }

            return "Unknown";
        }        

        /// <summary>
        /// 获取office文件类型
        /// </summary>
        /// <param name="fs"></param>
        /// <returns></returns>
        private static string GetOfficeFileType(Stream fs)
        {
            // Read more bytes to reach the "word/", "ppt/", or "xl/" folder
            byte[] buffer = new byte[2048];
            fs.Seek(0, SeekOrigin.Begin);
            fs.Read(buffer, 0, buffer.Length);

            string content = System.Text.Encoding.ASCII.GetString(buffer);

            if (content.Contains("[Content_Types].xml"))
            {
                if (content.Contains("word/"))
                {
                    return "DOCX";
                }
                if (content.Contains("ppt/"))
                {
                    return "PPTX";
                }
                if (content.Contains("xl/"))
                {
                    return "XLSX";
                }
            }

            return "Unknown ZIP-based Office file";
        }

        /// <summary>
        /// 比较文件头
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="signature"></param>
        /// <returns></returns>
        private static bool MatchesSignature(byte[] buffer, byte[] signature)
        {
            for (int i = 0; i < signature.Length; i++)
            {
                if (buffer[i] != signature[i])
                {
                    return false;
                }
            }
            return true;
        }

        /// <summary>
        /// 获得活动窗口的句柄
        /// </summary>
        /// <returns></returns>
        [DllImport("user32.dll", EntryPoint = "GetActiveWindow")]
        public static extern int GetActiveWindow();

        /// <summary>
        /// 写入INI文件
        /// </summary>
        /// <param name="section">节点名称[如[TypeName]]</param>
        /// <param name="key">键</param>
        /// <param name="val">值</param>
        /// <param name="filepath">文件路径</param>
        /// <returns>Long，非零表示成功，零表示失败。会设置GetLastError</returns>
        [System.Runtime.InteropServices.DllImport("kernel32")]
        private static extern long WritePrivateProfileString(string section, string key, string val, string iniPath);

        /// <summary>
        /// 读取INI文件
        /// </summary>
        /// <param name="section">节点名称</param>
        /// <param name="key">键</param>
        /// <param name="defval">值</param>
        /// <param name="retval">stringbulider对象</param>
        /// <param name="size">字节大小</param>
        /// <param name="iniPath">文件路径</param>
        /// <returns></returns>
        [System.Runtime.InteropServices.DllImport("kernel32")]
        private static extern int GetPrivateProfileString(string section, string key, string defval, StringBuilder retval, int size, string iniPath);
    }
}
